import { useState, useEffect, useRef } from "react";
import MarkdownRenderer from "./MarkdownRenderer";

interface TypewriterEffectProps {
  /** 完整的内容文本 */
  content: string;
  /** 每一步打字的延迟（毫秒） */
  typingSpeed?: number;
  /** 是否已经停止流式传输 */
  isComplete?: boolean;
  /** 是否允许渲染HTML */
  allowHtml?: boolean;
  /** 是否正在流式接收中，如果是，会调整打字速度更快 */
  isStreaming?: boolean;
}

/**
 * 打字机效果组件
 *
 * 将输入的文本以打字机效果逐字显示
 * 流式响应时，将新增内容加入队列，并以打字速度逐字显示
 * 只有当首个含有内容的流块到达时才开始渲染
 * 如果后续流块为空，则只显示光标闪烁
 */
const TypewriterEffect = ({
  content,
  typingSpeed = 20, // 默认打字速度
  isComplete = false,
  allowHtml = false,
  isStreaming = false,
}: TypewriterEffectProps) => {
  // 当前显示的文本内容
  const [displayedContent, setDisplayedContent] = useState("");
  // 控制是否暂停打字效果
  const [isPaused, setIsPaused] = useState(false);
  // 记录队列中待处理的文本
  const pendingTextRef = useRef("");
  // 记录前一次的完整内容
  const previousContentRef = useRef("");
  // 打字效果的每次增量字符数
  const charsPerTickRef = useRef(isStreaming ? 3 : 1);
  // 标记是否已经开始渲染（收到首个有内容的流块）
  const [hasStartedRendering, setHasStartedRendering] = useState(false);
  // 标记当前流块是否为空内容
  const [isCurrentContentEmpty, setIsCurrentContentEmpty] = useState(false);

  // 当内容变化时（新的流块到达）
  useEffect(() => {
    // 如果内容没变，不做任何处理
    if (content === previousContentRef.current) return;

    // 计算新增内容
    const newContent = content.substring(previousContentRef.current.length);

    // 检查新内容是否为空
    const isNewContentEmpty = newContent.trim().length === 0;

    // 更新前一次的内容记录
    previousContentRef.current = content;

    // 更新当前流块是否为空内容的状态
    setIsCurrentContentEmpty(isNewContentEmpty);

    // 如果新内容不为空，且之前未开始渲染，则标记为已开始渲染
    if (!isNewContentEmpty && !hasStartedRendering) {
      setHasStartedRendering(true);
    }

    // 只有当新内容不为空时，才添加到待处理队列
    if (!isNewContentEmpty) {
      // 将新内容添加到待处理队列
      pendingTextRef.current += newContent;

      // 如果打字效果暂停中，则重新启动
      if (isPaused) {
        setIsPaused(false);
      }
    }
  }, [content, isPaused, hasStartedRendering]);

  // 处理打字效果
  useEffect(() => {
    // 如果没有开始渲染（尚未收到首个有内容的流块），则不处理
    if (!hasStartedRendering) return;

    // 如果已完成（不再流式接收）并且显示内容等于完整内容，则不处理
    if (isComplete && displayedContent === content) return;

    // 调整打字速度：流式传输中时更快，完成后放慢
    charsPerTickRef.current = isStreaming ? 3 : 1;

    // 如果有待处理的文本，开始打字效果
    if (pendingTextRef.current.length > 0 && !isPaused) {
      const typingInterval = setInterval(() => {
        // 确定本次要添加的字符数量
        const charsToAdd = Math.min(
          charsPerTickRef.current,
          pendingTextRef.current.length
        );

        // 从待处理队列中取出要添加的字符
        const nextChars = pendingTextRef.current.substring(0, charsToAdd);
        pendingTextRef.current = pendingTextRef.current.substring(charsToAdd);

        // 更新显示内容
        setDisplayedContent((prev) => prev + nextChars);

        // 如果队列为空，暂停打字效果
        if (pendingTextRef.current.length === 0) {
          setIsPaused(true);
          clearInterval(typingInterval);

          // 如果流已经结束，但显示内容仍不完整，确保显示全部内容
          if (isComplete && displayedContent + nextChars !== content) {
            setDisplayedContent(content);
          }
        }
      }, typingSpeed);

      return () => clearInterval(typingInterval);
    }

    // 如果流结束并且有未显示的内容，立即显示所有内容
    if (isComplete && displayedContent !== content) {
      setDisplayedContent(content);
    }
  }, [
    content,
    displayedContent,
    isComplete,
    isPaused,
    isStreaming,
    typingSpeed,
    hasStartedRendering,
  ]);

  // 在完全流结束时确保显示全部内容
  useEffect(() => {
    if (isComplete && content !== displayedContent && hasStartedRendering) {
      setDisplayedContent(content);
    }
  }, [isComplete, content, displayedContent, hasStartedRendering]);

  // 如果尚未开始渲染（没有收到首个含内容的流块）
  if (!hasStartedRendering) {
    return (
      <div className="min-h-[1.5rem] flex items-center">
        <span className="typing-cursor inline-block h-4 w-1 bg-current opacity-75 animate-pulse" />
      </div>
    );
  }

  // 如果当前流块内容为空但已开始渲染，显示已渲染内容并添加闪烁光标
  if (isCurrentContentEmpty && isStreaming && !isComplete) {
    return (
      <div className="overflow-x-auto prose prose-base dark:prose-invert">
        <MarkdownRenderer content={displayedContent} allowHtml={allowHtml} />
        <span className="typing-cursor ml-1 inline-block h-4 w-1 bg-current opacity-75 animate-pulse" />
      </div>
    );
  }

  // 如果没有内容，返回一个空占位符
  if (!displayedContent) {
    return <div className="min-h-[1.5rem]"></div>;
  }

  // 渲染当前显示的内容
  return (
    <div className="overflow-x-auto prose prose-base dark:prose-invert">
      <MarkdownRenderer content={displayedContent} allowHtml={allowHtml} />
      {!isComplete &&
        displayedContent === content &&
        pendingTextRef.current.length === 0 && (
          <span className="typing-cursor ml-1 inline-block h-4 w-1 bg-current opacity-75 animate-pulse" />
        )}
    </div>
  );
};

export default TypewriterEffect;
